package com.suny.sf_server.util;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 布隆过滤器工具类
 */
@Slf4j
@Component
public class BloomFilterHelper {

    // 存储不同业务的布隆过滤器
    private static final ConcurrentHashMap<String, BloomFilter<String>> FILTER_MAP = new ConcurrentHashMap<>();

    /**
     * 初始化布隆过滤器
     *
     * @param business 业务标识
     * @param expectedInsertions 预期插入数量
     * @param fpp 误判率
     */
    public void initFilter(String business, int expectedInsertions, double fpp) {
        BloomFilter<String> filter = BloomFilter.create(
                Funnels.stringFunnel(Charset.defaultCharset()),
                expectedInsertions,
                fpp
        );
        FILTER_MAP.put(business, filter);
        log.info("初始化{}布隆过滤器成功", business);
    }

    /**
     * 批量添加元素
     *
     * @param business 业务标识
     * @param dataList 数据列表
     */
    public void addAll(String business, List<String> dataList) {
        BloomFilter<String> filter = getFilter(business);
        dataList.forEach(filter::put);
        log.info("{}布隆过滤器批量添加{}条数据", business, dataList.size());
    }

    /**
     * 添加元素
     *
     * @param business 业务标识
     * @param data 数据
     */
    public void add(String business, String data) {
        BloomFilter<String> filter = getFilter(business);
        filter.put(data);
    }

    /**
     * 判断元素是否可能存在
     *
     * @param business 业务标识
     * @param data 数据
     * @return true:可能存在 false:一定不存在
     */
    public boolean mightContain(String business, String data) {
        BloomFilter<String> filter = getFilter(business);
        return filter.mightContain(data);
    }

    /**
     * 获取指定业务的布隆过滤器
     *
     * @param business 业务标识
     * @return 布隆过滤器
     */
    private BloomFilter<String> getFilter(String business) {
        BloomFilter<String> filter = FILTER_MAP.get(business);
        if (filter == null) {
            throw new RuntimeException(String.format("布隆过滤器[%s]未初始化", business));
        }
        return filter;
    }

    /**
     * 重置布隆过滤器
     *
     * @param business 业务标识
     * @param expectedInsertions 预期插入数量
     * @param fpp 误判率
     */
    public void resetFilter(String business, int expectedInsertions, double fpp) {
        initFilter(business, expectedInsertions, fpp);
    }
}